/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
*
*
* Authors:                  zhoujian
* Email:            343600434@qq.com
* Date:         Mar-19-2024 11:55:21
*
*/


#include "rtc.h"

#include "log.h"
#include "main.h"
#include "spi.h"
#include "user_motor_drv.h"



RTC_zTypeDef rtc_state;
uint8_t alarm_on;

#if 0
RTC_DateType  RTC_DateStructure;
RTC_DateType  RTC_DateDefault;
RTC_TimeType  RTC_TimeStructure;
RTC_TimeType  RTC_TimeDefault;
RTC_InitType  RTC_InitStructure;
RTC_AlarmType RTC_AlarmStructure;
RTC_AlarmType RTC_AlarmDefault;
uint32_t SynchPrediv, AsynchPrediv;


uint8_t lse_ready_count;




void RTC_DateShow(void)
{
    /* Get the current Date */
    RTC_GetDate(RTC_FORMAT_BIN, &RTC_DateStructure);
    log_info("\n\r //=========== Current Date Display ==============// \n\r");
    log_info("\n\r The current date (WeekDay-Date-Month-Year) is :  %0.2d-%0.2d-%0.2d-%0.2d \n\r",
             RTC_DateStructure.WeekDay,
             RTC_DateStructure.Date,
             RTC_DateStructure.Month,
             RTC_DateStructure.Year);
}

/**
 * @brief  Display the current time on the Hyperterminal.
 */
void RTC_TimeShow(void)
{
    /* Get the current Time and Date */
    RTC_GetTime(RTC_FORMAT_BIN, &RTC_TimeStructure);
    log_info("\n\r //============ Current Time Display ===============// \n\r");
    log_info("\n\r The current time (Hour-Minute-Second) is :  %0.2d:%0.2d:%0.2d \n\r",
             RTC_TimeStructure.Hours,
             RTC_TimeStructure.Minutes,
             RTC_TimeStructure.Seconds);
    /* Unfreeze the RTC DAT Register */
    (void)RTC->DATE;
}
void RTC_AlarmShow(uint8_t AlarmX)
{
    /* Get the current Alarm */
    if(AlarmX == 0x01) {
        RTC_GetAlarm(RTC_FORMAT_BIN, RTC_A_ALARM, &RTC_AlarmStructure);

    } else {
        RTC_GetAlarm(RTC_FORMAT_BIN, RTC_B_ALARM, &RTC_AlarmStructure);
    }

    log_debug("\n\r //=========== Current Alarm Display ==============// \n\r");
    log_debug("\n\r The current alarm is :  %0.2d:%0.2d:%0.2d \n\r",
              RTC_AlarmStructure.AlarmTime.Hours,
              RTC_AlarmStructure.AlarmTime.Minutes,
              RTC_AlarmStructure.AlarmTime.Seconds);
}

void RTC_DateAndTimeDefaultVale(void)
{
    // Date
    RTC_DateDefault.WeekDay = 1;
    RTC_DateDefault.Date    = 01;
    RTC_DateDefault.Month   = 01;
    RTC_DateDefault.Year    = 24;
    // Time
    RTC_TimeDefault.H12     = RTC_AM_H12;
    RTC_TimeDefault.Hours   = 9;
    RTC_TimeDefault.Minutes = 00;
    RTC_TimeDefault.Seconds = 00;
    // Alarm
    RTC_AlarmDefault.AlarmTime.H12     = RTC_AM_H12;
    RTC_AlarmDefault.AlarmTime.Hours   = 9;
    RTC_AlarmDefault.AlarmTime.Minutes = 1;
    RTC_AlarmDefault.AlarmTime.Seconds = 00;
    RTC_AlarmDefault.DateWeekMode      = RTC_ALARM_SEL_WEEKDAY_DATE;
}


/**
 * @brief  Configures the RTC Source Clock Type.
 * @param Clk_Src_Type specifies RTC Source Clock Type.
 *   This parameter can be on of the following values:
 *     @arg RTC_CLK_SRC_TYPE_HSE128
 *     @arg RTC_CLK_SRC_TYPE_LSE
 *     @arg RTC_CLK_SRC_TYPE_LSI
 * @param Is_First_Cfg_RCC specifies Is First Config RCC Module.
 *   This parameter can be on of the following values:
 *     @arg true
 *     @arg false
 * @param Is_Rst_Bkp specifies Whether Reset The Backup Area
 *   This parameter can be on of the following values:
 *     @arg true
 *     @arg false
 */
void start_RTC_CLKSourceConfig()
{
    assert_param(IS_CLKSRC_VALUE(ClkSrc));
    assert_param(IS_FLCFG_VALUE(FirstLastCfg));
    /* Enable the PWR clock */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_PWR /*| RCC_APB1_PERIPH_BKP*/, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO, ENABLE);
    /* Allow access to RTC */
    //PWR_BackupAccessEnable(ENABLE);
    /* Reset Backup */
    /* Disable RTC clock */
    RCC_EnableRtcClk(DISABLE);
    //User_Delay_init();
    log_info("\r\n RTC_ClkSrc Is Set LSE! \r\n");
    /* Enable the LSE OSC32_IN PC14 */
    RCC_EnableLsi(DISABLE); // LSI is turned off here to ensure that only one clock is turned on
    //RCC_ConfigRtcClk(RCC_RTCCLK_SRC_LSE);
    RCC_ConfigLse(RCC_LSE_ENABLE);
    rtc_state = RTC_State_start_init;
}

uint8_t wait_RTC_CLKSourceConfig()
{
    uint8_t Status = 0;

    /****Waite LSE Ready *****/
    if((RCC_GetFlagStatus(RCC_FLAG_LSERD) == RESET) && (lse_ready_count < RTC_LSE_TRY_COUNT)) {
        lse_ready_count++;

        if(lse_ready_count >= RTC_LSE_TRY_COUNT) {
            Status = 2;
            log_info("\r\n RTC_ClkSrc Set LSE Faile! \r\n");

        } else {
            Status = 1;
        }

        return Status;
    }

    RCC_ConfigRtcClk(RCC_RTCCLK_SRC_LSE);
    SynchPrediv  = 0xFF; // 32.768KHz
    AsynchPrediv = 0x7F; // value range: 0-7F
    /* Enable the RTC Clock */
    RCC_EnableRtcClk(ENABLE);
    RTC_WaitForSynchro();
    return Status;
}

/**
 * @brief  RTC date regulate with the default value.
 */
ErrorStatus RTC_DateRegulate(void)
{
    uint32_t tmp_hh = 0xFF, tmp_mm = 0xFF, tmp_ss = 0xFF;
    log_info("\n\r //=============Date Settings================// \n\r");
    log_info("\n\r Please Set WeekDay (01-07) \n\r");
    tmp_hh = RTC_DateDefault.WeekDay;

    if(tmp_hh == 0xff) {
        return ERROR;

    } else {
        RTC_DateStructure.WeekDay = tmp_hh;
    }

    log_info(": %0.2d\n\r", tmp_hh);
    tmp_hh = 0xFF;
    log_info("\n\r Please Set Date (01-31) \n\r");
    tmp_hh = RTC_DateDefault.Date;

    if(tmp_hh == 0xff) {
        return ERROR;

    } else {
        RTC_DateStructure.Date = tmp_hh;
    }

    log_info(": %0.2d\n\r", tmp_hh);
    log_info("\n\r Please Set Month (01-12)\n\r");
    tmp_mm = RTC_DateDefault.Month;

    if(tmp_mm == 0xff) {
        return ERROR;

    } else {
        RTC_DateStructure.Month = tmp_mm;
    }

    log_info(": %0.2d\n\r", tmp_mm);
    log_info("\n\r Please Set Year (00-99)\n\r");
    tmp_ss = RTC_DateDefault.Year;

    if(tmp_ss == 0xff) {
        return ERROR;

    } else {
        RTC_DateStructure.Year = tmp_ss;
    }

    log_info(": %0.2d\n\r", tmp_ss);

    /* Configure the RTC date register */
    if(RTC_SetDate(RTC_FORMAT_BIN, &RTC_DateStructure) == ERROR) {
        log_info("\n\r>> !! RTC Set Date failed. !! <<\n\r");
        return ERROR;

    } else {
        log_info("\n\r>> !! RTC Set Date success. !! <<\n\r");
        RTC_DateShow();
        return SUCCESS;
    }
}

/**
 * @brief  RTC time regulate with the default value.
 */
ErrorStatus RTC_TimeRegulate(void)
{
    uint32_t tmp_hh = 0xFF, tmp_mm = 0xFF, tmp_ss = 0xFF;
    log_info("\n\r //==============Time Settings=================// \n\r");
    RTC_TimeStructure.H12 = RTC_TimeDefault.H12;
    log_info("\n\r Please Set Hours \n\r");
    tmp_hh = RTC_TimeDefault.Hours;

    if(tmp_hh == 0xff) {
        return ERROR;

    } else {
        RTC_TimeStructure.Hours = tmp_hh;
    }

    log_info(": %0.2d\n\r", tmp_hh);
    log_info("\n\r Please Set Minutes \n\r");
    tmp_mm = RTC_TimeDefault.Minutes;

    if(tmp_mm == 0xff) {
        return ERROR;

    } else {
        RTC_TimeStructure.Minutes = tmp_mm;
    }

    log_info(": %0.2d\n\r", tmp_mm);
    log_info("\n\r Please Set Seconds \n\r");
    tmp_ss = RTC_TimeDefault.Seconds;

    if(tmp_ss == 0xff) {
        return ERROR;

    } else {
        RTC_TimeStructure.Seconds = tmp_ss;
    }

    log_info(": %0.2d\n\r", tmp_ss);

    /* Configure the RTC time register */
    if(RTC_ConfigTime(RTC_FORMAT_BIN, &RTC_TimeStructure) == ERROR) {
        log_info("\n\r>> !! RTC Set Time failed. !! <<\n\r");
        return ERROR;

    } else {
        log_info("\n\r>> !! RTC Set Time success. !! <<\n\r");
        RTC_TimeShow();
        return SUCCESS;
    }
}
ErrorStatus RTC_AlarmRegulate(uint32_t RTC_Alarm)
{
    uint32_t tmp_hh = 0xFF, tmp_mm = 0xFF, tmp_ss = 0xFF;
    /* Disable the AlarmX */
    RTC_EnableAlarm(RTC_Alarm, DISABLE);
    log_info("\n\r //==============Alarm X Settings================// \n\r");
    RTC_AlarmStructure.AlarmTime.H12 = RTC_AM_H12;
    RTC_TimeStructure.H12            = RTC_AM_H12;
    log_info("\n\r Please Set Alarm Hours \n\r");
    tmp_hh = RTC_AlarmDefault.AlarmTime.Hours;

    if(tmp_hh == 0xff) {
        return ERROR;

    } else {
        RTC_AlarmStructure.AlarmTime.Hours = tmp_hh;
    }

    log_info(": %0.2d\n\r", tmp_hh);
    log_info("\n\r Please Set Alarm Minutes \n\r");
    tmp_mm = RTC_AlarmDefault.AlarmTime.Minutes;

    if(tmp_mm == 0xff) {
        return ERROR;

    } else {
        RTC_AlarmStructure.AlarmTime.Minutes = tmp_mm;
    }

    log_info(": %0.2d\n\r", tmp_mm);
    log_info("\n\r Please Set Alarm Seconds \n\r");
    tmp_ss = RTC_AlarmDefault.AlarmTime.Seconds;

    if(tmp_ss == 0xff) {
        return ERROR;

    } else {
        RTC_AlarmStructure.AlarmTime.Seconds = tmp_ss;
    }

    log_info(": %0.2d\n\r", tmp_ss);
    /* Set the Alarm X */
    RTC_AlarmStructure.DateWeekValue = 0x31;
    RTC_AlarmStructure.DateWeekMode = RTC_AlarmDefault.DateWeekMode;
    RTC_AlarmStructure.AlarmMask = RTC_ALARMMASK_WEEKDAY | RTC_ALARMMASK_HOURS | RTC_ALARMMASK_MINUTES;
    /* Configure the RTC Alarm A register */
    RTC_SetAlarm(RTC_FORMAT_BIN, RTC_Alarm, &RTC_AlarmStructure);
    log_info("\n\r>> !! RTC Set Alarm_X success. !! <<\n\r");

    if(RTC_Alarm == RTC_A_ALARM) {
        /* Enable the RTC Alarm A Interrupt */
        RTC_ConfigInt(RTC_INT_ALRA, ENABLE);
        RTC_AlarmShow(1);

    } else {
        /* Enable the RTC Alarm B Interrupt */
        RTC_ConfigInt(RTC_INT_ALRB, ENABLE);
        RTC_AlarmShow(2);
    }

    /* Enable the alarm   */
    RTC_EnableAlarm(RTC_Alarm, ENABLE);
    return SUCCESS;
}

void rtc_task0(void)
{
    uint8_t f;

    switch(rtc_state) {
        case RTC_State_0x00:
            rtc_state = RTC_State_0x00;
            break;

        case RTC_State_start_init:
            //lse_ready_count = 1;
            rtc_state = RTC_State_wait_init;
            break;

        case RTC_State_wait_init:

            //f = wait_RTC_CLKSourceConfig();
            if(f == 0) {
                rtc_state = RTC_State_init_success;

            } else if(f == 1) {
            } else {
                rtc_state = RTC_State_init_error;
            }

            break;

        case RTC_State_init_success:
            log_debug("rtc init success !\n");
            rtc_state = RTC_State_0x01;
            break;

        case RTC_State_init_error:
            rtc_state = RTC_State_0x00;
            break;

        case RTC_State_0x01:
            rtc_state = RTC_State_0x02;
            break;

        case RTC_State_0x02:
            rtc_state = RTC_State_0x03;
            break;

        case RTC_State_0x03:
            if(alarm_on == 1) {
                //power_off();
                log_debug("\t\t\t\t\t ----------- alarm 1\n");
                alarm_on = 0;
            }

            rtc_state = RTC_State_0x01;
            break;

        default:
            rtc_state = RTC_State_0x00;
            break;
    }
}

#endif
void power_off_hook(uint16_t line)
{
    log_error("power_off %d\n", line);
    rcu_periph_clock_enable(RCU_GPIOA);
    //gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11);
    //gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
#ifdef LINURM_DEBUG_MOTOR_TEST
#else
#ifdef LINURM_DEBUG_BATTERY_TEST
#else
    POWER_OFF;
#endif
#endif
}

void rtc_init_task(void)
{
    rtc_state = RTC_State_0x00;
#if 0
    //log_debug("sizeof(rtc_state)=%d\n", sizeof(rtc_state));
    RTC_DateAndTimeDefaultVale();
    //RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_PWR, ENABLE);
    //RTC_CLKSourceConfig(/*RTC_CLK_SRC_TYPE_LSE, true, false*/);
    start_RTC_CLKSourceConfig();
    /*RTC_DateRegulate();
    RTC_TimeRegulate();
    RTC_AlarmRegulate(RTC_A_ALARM);*/
#endif
    alarm_on = 0;
}
uint16_t idle_time = 0;

void rtc_task(void)//10ms
{
    //    uint8_t f;
    switch(rtc_state) {
        case RTC_State_0x00:
            rtc_state = RTC_State_0x01;
            break;

        case RTC_State_0x01:
            rtc_state = RTC_State_0x02;
            break;

        case RTC_State_0x02:
            rtc_state = RTC_State_0x03;
            break;

        case RTC_State_0x03:
            rtc_state = RTC_State_0x04;

            //if(idle_time++>45000){

            if(idle_time++ > 36000) {
                //if(idle_time++>100){
                //if(){
                //log_error("power_off\n");
                power_off();
                //}
                idle_time = 0;
            }

            break;

        default:
            rtc_state = RTC_State_0x00;
            break;
    }
}




